﻿using System.IO;
using System.Linq;
using System.Net;
using System.Xml;
using System.Xml.Serialization;

namespace GerbilLib
{
    /// <summary>
    /// Provides method to retrieve information from the themoviedb.org website.
    /// Please note that the TMDb API key is not provided as part of this class, it
    /// has to be passed into the constructor or static methods.
    /// </summary>
    public class TmdbScraper
    {
        /// <summary>
        /// Looks up movie metadata information from TMDb for a movie with the given IMDb ID.
        /// </summary>
        /// <param name="tmdbApiKey">The TMDb API key to get access to TMDb functionality.</param>
        /// <param name="imdbId">The IMDb id for the movie.</param>
        /// <returns>TmdbItem object with movie metadata for the title.</returns>
        public static TmdbItem MovieImdbLookup(string tmdbApiKey, string imdbId)
        {
            //WebRequest request = HttpWebRequest.Create("http://api.themoviedb.org/2.1/Movie.imdbLookup/en/xml/5ff6d68867c65c9234831e142d27896d/tt0398286");
            string requestString = string.Format("http://api.themoviedb.org/2.1/Movie.imdbLookup/en/xml/{0}/{1}", tmdbApiKey, imdbId);
            WebRequest request = HttpWebRequest.Create(requestString);
            WebResponse response;
            try
            {
                response = request.GetResponse();
            }
            catch (WebException ex)
            {
                Logger.LogMessage(string.Format("An error occurred while accessing the TMDb server: {0}", ex.Message));
                return null;
            }
            XmlSerializer x = new XmlSerializer(typeof(OpenSearchDescription));
            XmlReader text = XmlReader.Create(response.GetResponseStream());
            OpenSearchDescription osd = (OpenSearchDescription)x.Deserialize(text);
            text.Close();

            // Only grab the first returned movie result for now, as there should only be one for a given IMDb ID.
            TmdbItem item = null;
            if (osd.movies.Count() > 0) item = new TmdbItem(osd.movies[0]);
            return item;
        }

        /// <summary>
        /// Downloads and saves the highest resolution cover image from the TMDb image server using the image
        /// link provided in the TMDb meta data info for a title.
        /// </summary>
        /// <param name="item">Media Item for which to download the cover image.</param>
        /// <param name="imageSet">TMDb Image Set from which to download the cover image.</param>
        /// <returns>True if download was successful, otherwise false.</returns>
        public static bool SaveCoverImageToFolder(MediaItem item, TmdbImageSet imageSet)
        {
            if (imageSet.Original != null)
            {
                string path = string.Format("{0}{1}", item.Path, MediaItem.DefaultCoverImageFilename);
                FileDownloader download = new FileDownloader(imageSet.Original.Url);
                download.Download(path);
                item.HasCoverImage = true;

                return true;
            }

            return false;
        }

        /// <summary>
        /// Downloads and saves the specified cover image from the TMDb image server using the image
        /// link provided in the TMDb meta data info for a title.
        /// </summary>
        /// <param name="item">Media Item for which to download the cover image.</param>
        /// <param name="imageSet">TMDb Image Set from which to download the cover image.</param>
        /// <returns>True if download was successful, otherwise false.</returns>
        public static bool SaveCoverImageToFolder(MediaItem item, TmdbImage image)
        {
            if (image != null)
            {
                string path = string.Format("{0}{1}", item.Path, MediaItem.DefaultCoverImageFilename);
                FileDownloader download = new FileDownloader(image.Url);
                download.Download(path);
                item.HasCoverImage = true;

                return true;
            }

            return false;
        }

        /// <summary>
        /// Downloads and saves the first cover image for an item from the TMDb image server
        /// using the image link provided in the TMDb meta data info for the title.
        /// </summary>
        /// <param name="item">Media item for which to download the cover image.</param>
        /// <param name="tmdbApiKey">The TMDb API key to get access to TMDb functionality.</param>
        /// <returns>True if download was successful, otherwise false.</returns>
        public static bool SaveCoverImageToFolder(MediaItem item, string tmdbApiKey)
        {
            TmdbItem tmdbItem = MovieImdbLookup(tmdbApiKey, item.ImdbId);
            if (tmdbItem != null && tmdbItem.Posters.Count != 0)
                return SaveCoverImageToFolder(item, tmdbItem.Posters[0]);
            else return false;
        }

        /// <summary>
        /// Downloads and saves the specified backdrop image from the TMDb image server using the image
        /// link provided in the TMDb meta data info for a title.
        /// </summary>
        /// <param name="item">Media Item for which to download the backdrop image.</param>
        /// <param name="imageSet">TMDb Image Set from which to download the backdrop image.</param>
        /// <returns>True if download was successful, otherwise false.</returns>
        public static bool SaveBackdropImageToFolder(MediaItem item, TmdbImage image)
        {
            if (image != null)
            {
                string path = string.Format("{0}{1}", item.Path, GetNextBackdropImageFilename(item.Path));
                FileDownloader download = new FileDownloader(image.Url);
                download.Download(path);
                item.HasCoverImage = true;

                return true;
            }

            return false;
        }

        /// <summary>
        /// Returns the filename for the next backdrop image, so that backdrops are
        /// saved and enumerated in the way of backdrop.jpg, backdrop1.jpg, backdrop2.jpg etc.
        /// </summary>
        /// <param name="path">Path in which backdrop will be saved</param>
        /// <returns>Filename for backdrop image</returns>
        private static string GetNextBackdropImageFilename(string path)
        {
            if (!File.Exists(string.Format("{0}{1}", path, MediaItem.DefaultBackdropImageFilename)))
                return MediaItem.DefaultBackdropImageFilename;

            int backdropIndex = 1;
            string filename = string.Empty;
            do
            {
                // HACK: This is hardcoded to JPG right now, should be flexible to allow PNG or other formats as well
                filename = string.Format(MediaItem.DefaultBackdropImageFilename.Replace(".jpg", "{0}.jpg"), backdropIndex);
                backdropIndex++;
            }
            while (File.Exists(string.Format("{0}{1}", path, filename)));

            return filename;
        }
    }
}
